﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Windows.Forms;
using DesignerHelper.EventHandlers;
using DesignerHelper.Help;
using SpreadsheetGear;
using SpreadsheetGear.Windows.Forms;
using WorkbookDesigner.Properties;
using DesignerHelper.Main;

namespace WorkbookDesigner.Main
{
    public class FileOperator : IFileOperator
    {
        public FileOperator(IMainWindow mainWindow)
        {
            MainWindow = mainWindow;
            //MdiParent.
        }

        public IMainWindow MainWindow { get; }

        #region FormManager

        public event EventHandler<BookSetEventArgs> BookSetModified;

        public event CellBeginEditEventHandler CellBeginEditInternal;

        public event CellCancelEditEventHandler CellCancelEditInternal;

        public event CellEndEditEventHandler CellEndEditInternal;

        public event DisableUIEventHandler DisableUI;

        public event EnableUIEventHandler EnableUI;

        public event RangeSelectionChangedEventHandler RangeSelectionChangedInternal;


        public IList<IBookForm> AllFormsList { get; private set; }
        public IWorkbookSet MainBookSet { get; private set; }

        public List<WorkbookView> ViewList
        {
            get { return AllFormsList.Select(x => x.WorkbookView).ToList(); }
        }

        internal void InitManager()
        {
            IWorkbookSet newBookSet = Factory.GetWorkbookSet();
            newBookSet.DefaultFontName = "微软雅黑";
            newBookSet.DefaultFontSize = 10;
            TriggerInitManager(newBookSet);
        }

        internal void InitManager(IWorkbookSet bookSet)
        {
            TriggerInitManager(bookSet);
        }

        private void OnBookSetModified(object sender, BookSetEventArgs e)
        {
            BookSetModified?.Invoke(sender, e);
        }

        private void OnCellBeginEditInternalEventHandler(object sender, CellBeginEditEventArgs e)
        {
            CellBeginEditInternal?.Invoke(sender, e);
        }

        private void OnCellCancelEditInternalEventHandler(object sender, CellCancelEditEventArgs e)
        {
            CellCancelEditInternal?.Invoke(sender, e);
        }

        private void OnCellEndlEditInternalEventHandler(object sender, CellEndEditEventArgs e)
        {
            CellEndEditInternal?.Invoke(sender, e);
        }

        private void OnDisableUI(NoFormLeftEventArgs e)
        {
            DisableUI?.Invoke(this, e);
        }

        private void OnEnableUI(FormExistEventArgs e)
        {
            EnableUI?.Invoke(this, e);
        }

        private void OnRangeSelectionChangedInternalEventHandler(object sender, RangeSelectionChangedEventArgs e)
        {
            RangeSelectionChangedInternal?.Invoke(sender, e);
        }

        private void TriggerInitManager(IWorkbookSet bookSet)
        {
            MainBookSet = bookSet;
            if (AllFormsList == null)
                AllFormsList = new List<IBookForm>();
        }

        #endregion


        #region Open File


        void IFileOperator.OpenFile(string fileLocation)
        {
            OpenFile(fileLocation);
        }

        void IFileOperator.OpenFile(IWorkbook workbook)
        {
            OpenFile(workbook);
        }

        void IFileOperator.OpenWorkbooks()
        {
            OpenWorkbooks();
        }
        void IFileOperator.OpenFiles()
        {
            OpenFiles();
        }


        internal void OpenFile(string fileLocation)
        {
            MainBookSet.DoWork(() =>
            {
                try
                {
                    if (AllFormsList.All(workBookForm => workBookForm.ActiveBook.FullName != fileLocation))
                    {
                        IWorkbook book = MainBookSet.Workbooks.Open(fileLocation);
                        WorkBookForm form = new WorkBookForm(book, MainWindow)
                        {
                            Text = fileLocation,
                        };
                        form.Show();
                        CheckEvent_Add(form);

                    }
                    else
                    {
                        MesBox.InfoMessage("文件 " + fileLocation + " 已经打开!");
                    }
                }
                catch (DirectoryNotFoundException dex)
                {
                    MesBox.ErrorMessage(dex);
                }
                catch (FileNotFoundException fex)
                {
                    MesBox.ErrorMessage(fex);
                }
            });
        }

        internal void OpenFile(IWorkbook book)
        {
            MainBookSet.DoWork(() =>
            {
                if (AllFormsList.All(form => form.ActiveBook != book))
                {
                    WorkBookForm form = new WorkBookForm(book, MainWindow)
                    {
                        Text = book.FullName,

                    };
                    form.Show();
                    CheckEvent_Add(form);
                }
                else
                {
                    //MesBox.InfoMessage("文件 " + book.FullName + " 已经打开!");
                }
            });
        }

        internal void OpenWorkbooks()
        {
            MainBookSet.DoWork(() =>
            {
                IWorkbooks books = MainBookSet.Workbooks;
                foreach (IWorkbook book in books)
                {
                    OpenFile(book);
                }

            });
        }

        internal void OpenFiles()
        {
            using (OpenFileDialog openFile = OpenFileDia())
            {
                if (openFile.ShowDialog() != DialogResult.OK)
                    return;
                var fileLocations = openFile.FileNames;
                foreach (string fileLocation in fileLocations)
                {
                    OpenFile(fileLocation);
                }
            }
        }
        private static OpenFileDialog OpenFileDia()
        {
            OpenFileDialog openFile = new OpenFileDialog
            {
                Multiselect = true,
                Filter = Resources.FileDialogFormatFilter,
                FilterIndex = 1,
                CheckFileExists = true,
                CheckPathExists = true
            };
            return openFile;
        }

        private bool CheckEvent_Add(IBookForm form)
        {
            if (AllFormsList.Contains(form))
                return false;
            AllFormsList.Add(form);
            //form.GetForm().FormClosed += Handler_FormClosed;
            form.GetForm().Disposed += Handler_FormDisposed;
            form.Editor.BookIsModified += OnBookSetModified;
            form.WorkbookView.CellBeginEdit += OnCellBeginEditInternalEventHandler;
            form.WorkbookView.CellCancelEdit += OnCellCancelEditInternalEventHandler;
            form.WorkbookView.CellEndEdit += OnCellEndlEditInternalEventHandler;
            form.WorkbookView.RangeSelectionChanged += OnRangeSelectionChangedInternalEventHandler;
            if (AllFormsList.Count == 1)
                OnEnableUI(new FormExistEventArgs(AllFormsList.Count));
            OnBookSetModified(form, new BookSetEventArgs(MainWindow.ActiveBookForm?.ActiveBook, BookSetEventArgs.Type.Refresh));
            return true;
        }
        private void Handler_FormClosed(object sender, EventArgs e)
        {
            WorkBookForm form = sender as WorkBookForm;
            if (form == null) return;
            Close(form);
        }

        private void Handler_FormDisposed(object sender, EventArgs e)
        {
            if (MainWindow.ActiveBookForm != null)
                OnBookSetModified(MainWindow.ActiveBookForm,
                    new BookSetEventArgs(MainWindow.ActiveBookForm.ActiveBook, BookSetEventArgs.Type.Refresh));
        }
        #endregion

        #region New File

        void IFileOperator.NewFile()
        {
            NewFile();
        }

        internal void NewFile()
        {
            MainBookSet.DoWork(() =>
            {
                IWorkbook newBook = MainBookSet.Workbooks.Add();
                WorkBookForm form = new WorkBookForm(newBook, MainWindow)
                {
                    Text = newBook.FullName,
                };
                form.Show();
                CheckEvent_Add(form);
            });
        }

        #endregion


        #region Close File

        public void Close(IWorkbook workbook)
        {
            var form = AllFormsList.FirstOrDefault(x => x.ActiveBook == workbook);
            Close(form);
        }

        public void Close(IBookForm form)
        {
            MainBookSet.DoWork(() =>
            {
                try
                {
                    form.ActiveBook.Close();
                    AllFormsList.Remove(form);
                    form.Editor.BookIsModified -= OnBookSetModified;
                    form.WorkbookView.CellBeginEdit -= OnCellBeginEditInternalEventHandler;
                    form.WorkbookView.CellCancelEdit -= OnCellCancelEditInternalEventHandler;
                    form.WorkbookView.CellEndEdit -= OnCellEndlEditInternalEventHandler;
                    form.WorkbookView.RangeSelectionChanged -= OnRangeSelectionChangedInternalEventHandler;
                    if (AllFormsList.Count == 0)
                        OnDisableUI(new NoFormLeftEventArgs());
                    if(MainWindow.ActiveBookForm != null)
                        OnBookSetModified(MainWindow.ActiveBookForm, new BookSetEventArgs(MainWindow.ActiveBookForm?.ActiveBook, BookSetEventArgs.Type.Refresh));

                }
                catch (InvalidOperationException ioe)
                {
                    MesBox.ErrorMessage(ioe);
                }
                catch (ArgumentNullException ane)
                {
                    MesBox.ErrorMessage(ane);
                }
            });
        }

        #endregion

        public void SaveFile(IBookForm form)
        {
            WorkbookView wbv = form.WorkbookView;
            IWorkbook workbook = wbv.ActiveWorkbook;
            if (workbook.FullName == workbook.Name && workbook.Name.StartsWith("Book"))//ps 可能需要改进文件保存逻辑
                FileSaveAs(form);
            else
            {
                try
                {
                    wbv.DoWork(workbook.Save);
                    //OnBookIsModified(new BookSetEventArgs(workbook, BookSetEventArgs.Type.Refresh));
                }
                catch (IOException ioEx)
                {
                    MesBox.ErrorMessage(ioEx);
                }

            }
        }
        public void FileSaveAs(IBookForm form)
        {

            WorkbookView wbv = form.WorkbookView;
            IWorkbook book = wbv.ActiveWorkbook;
            using (SaveFileDialog savefile = GetSaveFileDialog(book.Name))
            {
                switch (savefile.ShowDialog())
                {
                    case DialogResult.OK:
                        wbv.DoWork(() =>
                        {
                            // ReSharper disable once AccessToDisposedClosure
                            book.SaveAs(savefile.FileName, GetFileformat(book, savefile.FilterIndex));//ps check null?
                        });
                        //OnBookIsModified(new BookSetEventArgs(book, BookSetEventArgs.Type.Refresh));
                        form.GetForm().Text = savefile.FileName;
                        MesBox.InfoMessage("成功保存文件至路径 " + '\n' + savefile.FileName);
                        break;
                    case DialogResult.Cancel:
                        break;
                    default:
                        break;
                }
            }
        }

        private static SaveFileDialog GetSaveFileDialog(string fileName)
        {
            SaveFileDialog savefile = new SaveFileDialog
            {
                Filter = Properties.Resources.FileDialogFormatFilter,
                FilterIndex = 2,
                OverwritePrompt = true,
                FileName = fileName,
                CheckPathExists = true,
                ValidateNames = true,
                AutoUpgradeEnabled = true,
            };
            return savefile;
        }

        private FileFormat GetFileformat(IWorkbook book, int filterIndex)
        {
            switch (filterIndex)
            {
                case 2:
                    return FileFormat.OpenXMLWorkbook;

                case 3:
                    return FileFormat.Excel8;

                case 4:
                    return FileFormat.CSV;

                default:
                    return book.FileFormat;
            }
        }

    }
}